/*
Copyright 2016 Capital One Services, LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.

SPDX-Copyright: Copyright (c) Capital One Services, LLC
SPDX-License-Identifier: Apache-2.0
*/

import extractProps from 'react-native-svg/lib/extract/extractProps';
import React, {Component} from 'react'
import {Text as ReactText, Animated} from 'react-native'
import Svg, {G, Path, Text, Circle, LinearGradient, Stop,Line} from 'react-native-svg'
import {Colors, Options, cyclic, identity, fontAdapt} from './util'
import _ from 'lodash'

const Pie = require('paths-js/pie')

const ANIMATION_START_DELAY = 1000;

export default class PieChart extends Component {

  static defaultProps = {
    options: {
      margin: {top: 40, left: 40, right: 40, bottom: 40},
      width: 600,
      height: 600,
      color: '#2980B9',
      r: 100,
      R: 200,
      legendPosition: 'topLeft',
      label: {
        fontFamily: 'Arial',
        fontSize: 14,
        bold: true,
        color: '#ECF0F1'
      }
    },
  }

  constructor(props) {
    super(props);
    this.state = {
      expanded: Array.from({length: props.data.length}).map(() => 0),
    }
  }


  color(i) {
    let color = this.props.color || (this.props.options && this.props.options.color);
    if (Array.isArray(color)) {
      if (i >= color.length) {
        const pallete = Colors.mix(color[i % color.length]);
        return Colors.string(cyclic(pallete, i))
      }
      return color[i];
    } else {
      if (color && !_.isString(color)) color = color.color;
      let pallete = this.props.pallete || (this.props.options && this.props.options.pallete) || Colors.mix(color || '#9ac7f7');
      return Colors.string(cyclic(pallete, i))
    }
  }

  expand = (i) => {
    const target = Array.from({length: this.props.data.length}).map(() => 0);
    target[i] = 1;
    this.setState({expanded: target});
  };

  translate = (p) => {
    return "translate(" + p[0] + "," + p[1] + ")"
  };

  move = (point, perc, {centerX, centerY}) => {
    const factorX = (point[0] - centerX) > 0 ? 1 : -1;
    const factorY = (point[1] - centerY) > 0 ? 1 : -1;
    return this.translate([point[0] * perc / 30 * factorX, point[1] * perc / 30 * factorY]);
  };

  //文字适应屏幕的高度
  textPosition=(position,center,type)=>{
    if(position[1]>center){
      return this.textLinePosition(position,center,type);
    }else {
      if(type==='x'){
        return this.textLinePosition(position,center,type)-15;
      }else {
        return this.textLinePosition(position,center,type)-30;
      }
    }
  }

  textLinePosition=(position,center,type)=>{
    let positionXY,factor;
    if(type==='x'){
      positionXY = position[0]
    }else {
      positionXY = position[1]
    }
     factor = positionXY-center>0?1:-1;
    return positionXY+70*factor;
  }

  grad = (i) => {
    return "grad-" + i
  };

  lighten = (i) => {
    let color = this.props.color || (this.props.options && this.props.options.color);
    if (Array.isArray(color)) {
      if (i >= color.length) {
        const pallete = Colors.mix(color[i % color.length]);
        return Colors.string(cyclic(pallete, i))
      }
      return color[i];
    } else {
      if (color && !_.isString(color)) color = color.color;
      let pallete = this.props.pallete || (this.props.options && this.props.options.pallete) || Colors.mix(color || '#9ac7f7');
      return Colors.string(Colors.lighten(cyclic(pallete, i)));
    }
  };

  fill = (i) => {
    return "url(#grad-" + i + ")"
  };

  get defaultRange() {
    return _.map(Array(this.props.data && this.props.data.length), function () {
      return 0
    })
  }


  render() {
    const noDataMsg = this.props.noDataMessage || 'No data available'
    if (this.props.data === undefined) return (<ReactText>{noDataMsg}</ReactText>)

    let options = new Options(this.props)

    let x = (options.chartWidth / 2) - (options.margin.left || 0);
    let y = (options.chartHeight / 2) - (options.margin.top || 0);

    let radius = Math.min(x, y);

    let r = this.props.r;
    r = (isNaN(r) ? (this.props.options && this.props.options.r) : r);
    r = (isNaN(r) ? (radius / 2) : r);

    let R = this.props.R;
    R = (R || (this.props.options && this.props.options.R));
    R = (R || radius);

    let [centerX, centerY] = this.props.center || (this.props.options && this.props.options.center) || [x, y];

    let textStyle = fontAdapt(options.label);

    let slices;

    if (this.props.data.length === 1) {//只有一条数据时候使用
      let item = this.props.data[0];
      let outerFill = (item.color && Colors.string(item.color)) || this.color(0);
      let innerFill = this.props.monoItemInnerFillColor || '#fff';
      let stroke = typeof fill === 'string' ? outerFill : Colors.darkenColor(outerFill);
      slices = (
        <G>
          <Circle r={R} cx={centerX} cy={centerY} stroke={stroke} fill={outerFill}/>
          <Circle r={r} cx={centerX} cy={centerY} stroke={stroke} fill={innerFill}/>
          <Text fontFamily={textStyle.fontFamily}
                fontSize={textStyle.fontSize}
                fontWeight={textStyle.fontWeight}
                fontStyle={textStyle.fontStyle}
                fill={textStyle.fill}
                textAnchor="middle"
                x={centerX}
                y={centerY - R + ((R - r) / 2)}>{item.name}</Text>
        </G>
      )
    } else {
      let chart = Pie({//用'paths-js/pie'处理数据
        center: [centerX, centerY],
        r,
        R,
        data: this.props.data,
        accessor: this.props.accessor || identity(this.props.accessorKey)
      })

      const coefficients = this.state.expanded;

      slices = chart.curves.map((c, i) => {
        let fill = (c.item.color && Colors.string(c.item.color)) || this.color(i)
        let stroke = typeof fill === 'string' ? fill : Colors.darkenColor(fill)
        const opacity = 1
        const finalStroke = stroke;


        return (
          <G key={i}
             transform={this.move(c.sector.centroid, coefficients[i], {centerX, centerY})}
             onPressIn={() => this.expand(i)}>
            <LinearGradient id={this.grad(i)}>
              <Stop stopColor={this.color(i)} offset="0%" stopOpacity="0"/>
              <Stop stopColor={this.lighten(i)} offset="100%" stopOpacity="1"/>
            </LinearGradient>
            {/*绘制单个饼状*/}
            <Path fill={this.fill(i)} fillOpacity={opacity}
                  d={c.sector.path.print()} stroke={finalStroke}/>
            {/*设置文字的偏移量*/}
            <G x={options.margin.left} y={options.margin.top}>
              <Text fontFamily={textStyle.fontFamily}
                    fontSize={textStyle.fontSize}
                    fontWeight={textStyle.fontWeight}
                    fontStyle={textStyle.fontStyle}
                    fill={textStyle.fill}
                    textAnchor="middle"
                    x={this.textPosition(c.sector.centroid,centerX,'x')}
                    y={this.textPosition(c.sector.centroid,centerY,'y')}>{c.item.name}</Text>
            </G>
            <Line
              x1={c.sector.centroid[0]}
              y1={c.sector.centroid[1]}
              x2={this.textLinePosition(c.sector.centroid,centerX,'x')}
              y2={this.textLinePosition(c.sector.centroid,centerY,'y')}
              stroke="red"
              strokeWidth="2"
            />
          </G>
        )
      })
    }


    let returnValue = <Svg width={options.width} height={options.height}>
      <G x={options.margin.left} y={options.margin.top}>
        {slices}
      </G>
    </Svg>

    return returnValue
  }
}
